/*! Header of FunctorsCarHire
*/
#ifndef FUNCTORS_CARHIRE_H
#define FUNCTORS_CARHIRE_H

#include <string>

//! FunctorsCarHire is a collection of functors needed in the CarHire
/*!
	FunctorsCarHire.h includes all the functors needed by the CarHire
	to print cars or add cars to a list.
	\author Andreas Lehner
	\date 22.11.2012
*/

//a list of Cars
typedef std::list<ICar*> TCars;

//! A functor which is calling Print() for every Car in a list
/*! 
	This functor puts out a car to a given stream with all of
	its information including the car class, manufacturer,
	type, price without extras, price of every extra
	added in the car and the extra itself and also the total
	price of the requested car plus extra(s).
*/
class PrintCars : public std::unary_function<ICar*, void>{
public:
	//! CTor of functor PrintCars
	/*! 
		The constructor stores the stream,
		where the output should be written
		to an intern variable.
		\param stream The output stream where information is printed to
	*/
	PrintCars(std::ostream &stream): mStream(stream){}
	//! operator() overloaded
	/*! 
		Uses the Print() function of the interface to print out all
		information the car has plus its total price.
	*/
	void operator()(ICar* car){
		car->Print(mStream);
		mStream << "Total price: EUR " << car->GetPrice() << std::endl << std::endl;
	}
private:
	//ostream for printing
	std::ostream &mStream;
};
//! A functor which is calling Print() for every Car in a list
/*! 
	This functor adds cars according to a certain manufacturer,
	type or both to a list of ICar*. A getter function is
	used to return the list of cars.
*/
class GetCars : public std::unary_function<ICar*, void>{
public:
	//! CTor of functor GetCars
	/*! 
		The constructor stores the information of
		the car (manufacturer and type) in variables.
		\param manufacturer The manufactuer of a car
		\param type The type of a car
	*/
	GetCars(std::string const& manufacturer, std::string const& type):
		mManufacturer(manufacturer), mType(type){}
	//! operator() overloaded
	/*! 
		This function compares the manufacturer of the car
		with the manufacturer committed and the type of the
		car with the type commited.
		If there is no statement given (string of manufacturer
		and type are empty) all cars will be added to the list.
		\param car The car to be added to the list
	*/
	void operator()(ICar* car){
		if (car == 0){
			throw std::exception("invalid pointer of type ICar");
		}
		//if no statement is given, add all cars
		if (mManufacturer == "" && mType == ""){
			mCars.push_back(car);
		}
		//add all cars of a certain type and all manufacturers
		else if (mManufacturer == ""){
			if (car->GetType() == mType){
				mCars.push_back(car);
			}
		}
		//add all cars of a certain manufacturer and all types
		else if (mType == ""){
			if (car->GetManufacturer() == mManufacturer){
				mCars.push_back(car);
			}
		}
		//add all cars of a certain type and manufacturer
		else if (car->GetType() == mType && car->GetManufacturer() == mManufacturer){
			mCars.push_back(car);
		}
	}
	//! getter for retrieving the list of cars
	/*! 
		The getter returns the list just created.
		All cars that match the information are stored
		in this list.
		\return TCars The list of cars
	*/
	TCars GetCarList() const{
		return mCars;
	}
private:
	//car manufacturer
	std::string mManufacturer;
	//car type
	std::string mType;
	//list of cars that match witch the search strings
	TCars mCars;
};

#endif